<?php
namespace ulue\parts\security;


/**
 *
 * Usage:
 *
 * $user = $db->query(['name' => $_POST['name'] ]);
 *
 * 1.
 *  gen:
 *      $password = Token::gen('123456');
 *  verify:
 *      Token::verify($user['password'], '123456');
 *
 * 2.
 *  gen:
 *      $password = Token::hash('123456');
 *  verify:
 *      Token::verifyHash($user['password'], '123456');
 */
class Token
{
    /**
     * 指明应该使用的算法
     * $2a BLOWFISH算法。
     * $5  SHA-256
     * $6  SHA-512
     * @var string
     */
    static private $algo = '$2a';

    /**
     * cost parameter 就是成本参数
     * $10 这是以2为底的对数，指示计算循环迭代的次数（10 => 2^10 = 1024），取值可以从04到31。
     * @var string
     */
    static private $cost = '$10';

    // mainly for internal use
    static public function unique_salt()
    {
        return substr(sha1(mt_rand()),0,22);
    }

    // this will be used to generate a hash
    static public function gen($password)
    {
        return crypt($password,
            self::$algo .
            self::$cost .
            '$'. self::unique_salt()
        );
    }

    // this will be used to compare a password against a hash
    static public function verify($hash, $password)
    {
        $full_salt = substr($hash, 0, 29);
        $new_hash  = crypt($password, $full_salt);

        return ($hash === $new_hash);
    }

    //2 生成
    //@todo from php.net
    static public function hash($password, $cost=11)
    {
        /* To generate the salt, first generate enough random bytes. Because
         * base64 returns one character for each 6 bits, the we should generate
         * at least 22*6/8=16.5 bytes, so we generate 17. Then we get the first
         * 22 base64 characters
         */
        $salt = substr(base64_encode(openssl_random_pseudo_bytes(17)),0,22);
        /* As blowfish takes a salt with the alphabet ./A-Za-z0-9 we have to
         * replace any '+' in the base64 string with '.'. We don't have to do
         * anything about the '=', as this only occurs when the b64 string is
         * padded, which is always after the first 22 characters.
         */
        $salt = str_replace("+",".",$salt);
        /* Next, create a string that will be passed to crypt, containing all
         * of the settings, separated by dollar signs
         */
        $param='$'.implode('$',array(
              "2x", //select the most secure version of blowfish (>=PHP 5.3.7)
              str_pad($cost,2,"0",STR_PAD_LEFT), //add the cost in two digits
              $salt //add the salt
        ));

        //now do the actual hashing
        return crypt($password,$param);
    }

    /**
     * 2 验证
     * Check the password against a hash generated by the generate_hash
     * function.
     */
    static public function verifyHash($hash, $password)
    {
      /* Regenerating the with an available hash as the options parameter should
       * produce the same hash if the same password is passed.
       */
      return crypt($password, $hash)==$hash ? true: false;
    }

    /**
     * 生成guid
     * @return string
     */
    static public function guid()
    {
        mt_srand((double)microtime()*10000);

        $charid = strtolower(md5(uniqid(rand(), true)));
        $hyphen = chr(45);
        $uuid   = substr($charid, 0, 8).
            substr($charid, 8, 4).
            substr($charid,12, 4).
            substr($charid,16, 4).
            substr($charid,20,12);

        return $uuid;
    }

    /**
     * *******生成唯一序列号*******
     * @param $var array || obj
     * @return string
     */
    static public function md5($var)
    {
        //serialize()序列化，串行化
        return md5(serialize($var));
    }
}